/*
 * IpAddress.java
 *
 * Created on 2003年3月10日, 下午4:43
 */

package com.ultrapower.ultracsa.product.util;

import java.util.ArrayList;
import java.util.Properties;
import java.util.StringTokenizer;

/**
 *
 * @author  Administrator
 */
public class IpAddressUtil  {
    
    final static int INADDRSZ = 4;
    
    /** Holds value of property ip. */
    private String ip;
    
    /** Holds value of property netmask. */
    private String netmask;
    
    /** Holds value of property netip. */
    private String netip;
    
    /** Creates a new instance of IpAddress */
    public IpAddressUtil(String ip, String netmask) {
        this.ip = ip;
        this.netmask = netmask;
        this.netip = getNetAdd(ip, netmask);
    }
    
    
    /** Getter for property ip.
     * @return Value of property ip.
     *
     */
    public String getIp() {
        return this.ip;
    }
    
    
    /** Getter for property netmask.
     * @return Value of property netmask.
     *
     */
    public String getNetmask() {
        return this.netmask;
    }
    
    /** Getter for property netip.
     * @return Value of property netip.
     *
     */
    public String getNetip() {
        return getNetAdd(ip, netmask);
    }
    
    private String getNetAdd(String ipaddress,String netmask) {
        String netAdd;
        byte[] src1,src2;
        src1=textToNumericFormat(ipaddress);
        src2=textToNumericFormat(netmask);
        netAdd=((src1[0]) & (src2[0]) & 0xff )+".";
        netAdd=netAdd+((src1[1]) & (src2[1]) & 0xff )+".";
        netAdd=netAdd+((src1[2]) & (src2[2]) & 0xff )+".";
        netAdd=netAdd+((src1[3]) & (src2[3]) & 0xff );
        return netAdd;
    }
    
    // Utilities
    /*
     * Converts IPv4 binary address into a string suitable for presentation.
     *
     * @param src a byte array representing an IPv4 numeric address
     * @return a String representing the IPv4 address in
     *         textual representation format
     * @since 1.4
     */
    
    private static String numericToTextFormat(byte[] src) {
        return (src[0] & 0xff) + "." + (src[1] & 0xff) + "." + (src[2] & 0xff) + "." + (src[3] & 0xff);
    }
    
    /*
     * Converts IPv4 address in its textual presentation form
     * into its numeric binary form.
     *
     * @param src a String representing an IPv4 address in standard format
     * @return a byte array representing the IPv4 numeric address
     * @since 1.4
     */
    private static byte[] textToNumericFormat(String src) {
        if (src.length() == 0) {
            return null;
        }
        
        int octets;
        char ch;
        byte[] dst = new byte[INADDRSZ];
        char[] srcb = src.toCharArray();
        boolean saw_digit = false;
        
        octets = 0;
        int i = 0;
        int cur = 0;
        while (i < srcb.length) {
            ch = srcb[i++];
            if (Character.isDigit(ch)) {
                int sum =  dst[cur]*10 + (Character.digit(ch, 10) & 0xff);
                
                if (sum > 255)
                    return null;
                
                dst[cur] = (byte)(sum & 0xff);
                if (! saw_digit) {
                    if (++octets > INADDRSZ)
                        return null;
                    saw_digit = true;
                }
            } else if (ch == '.' && saw_digit) {
                if (octets == INADDRSZ)
                    return null;
                cur++;
                dst[cur] = 0;
                saw_digit = false;
            } else
                return null;
        }
        if (octets < INADDRSZ)
            return null;
        return dst;
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        System.out.println(isBigger("218.201.86.129","218.201.86.113"));
    }
    
    /** convert a ip address to a long variable
     *
     */
    public long getAddrLong() {
        int aip[] = getAddrArray(ip);
        if(aip == null) {
            System.out.println("Invalid ip address argument. " + ip );
            return 0L;
        }
        long result = 0L;
        for(int i = 0; i < 4; i++)
            result |= (long)aip[i] << 8 * (3 - i);
        
        return result;
    }
    
    /** convert a ip to a int array
     *
     */
    private static int[] getAddrArray(String ip) {
        if(ip == null)
            return null;
        StringTokenizer stringtokenizer = new StringTokenizer(ip, ".");
        if(stringtokenizer.countTokens() != 4)
            return null;
        int aip[] = new int[4];
        try {
            for(int i = 0; i < 4; i++)
                aip[i] = Integer.parseInt(stringtokenizer.nextToken());
            
        }
        catch(NumberFormatException numberformatexception) {
            return null;
        }
        for(int j = 0; j < 4; j++)
            if(aip[j] < 0 || aip[j] > 255)
                return null;
        
        return aip;
    }
    
    /** get the maximum ip from the given ip list
     * return maximu ip in a string
     * 最大IP地址，并且要保证返回的IP是能ping通的IP地址
     */
    private static IpAddressUtil getMaxIp(ArrayList iplist) {
        if ( iplist == null || iplist.size() < 1 )
            return null;
        IpAddressUtil result = null;
        IpAddressUtil temp = (IpAddressUtil)iplist.get(0);
        result = temp.getIp().startsWith("127") ? (null) : temp ;
        for (int i = 1; i<iplist.size(); i++) {
            temp = (IpAddressUtil)iplist.get(i);
            if ( temp.getIp().startsWith("127") )
                continue;
            if ( result == null )
                result = temp;
            else if ( isBigger(temp.getIp(), result.getIp())  ) {
                result = temp;
            }
        }
        
        if ( result != null ){
            if ( !( PingUtil.ping(result.getIp(),2,3000) ) ){ //ping不通
                for ( int j = 0; j < iplist.size(); j++ ){
                    if ( ((IpAddressUtil)iplist.get(j)).getIp().equalsIgnoreCase(result.getIp()) )
                        iplist.remove(j);
                }
                result = getMaxIp(iplist);
            }
        }
        
        return result;
    }
    
    /** get main ip of a router, now consider the loopback ip as main ip
     * 得到主IP，优先用loopback ip， 再用最大IP地址，并且要保证返回的IP是能ping通的IP地址
     */
    public static IpAddressUtil getMainIp(ArrayList values) {
        
        if ( values == null )
            return null;
        
        int size = values.size();
        
        if ( size < 1 )
            return null;
        
        ArrayList ip_list = new ArrayList();
        for (int i = 0; i< size;i++){
            Properties p = (Properties) values.get(i);
            String ip = p.getProperty("ipAdEntAddr");
            String mask = p.getProperty("ipAdEntNetMask");
            IpAddressUtil temp_ip = new IpAddressUtil(ip,mask);
            
            if( mask.equals("255.255.255.255") && !(ip.startsWith("127")) && !(ip.startsWith("0")) && PingUtil.ping(ip,2,3000) ){
                return temp_ip;
            }
            if ( ip!=null && !ip.startsWith("0") && !ip.startsWith("127"))
                ip_list.add(temp_ip);
        }
        
        return getMaxIp(ip_list);
    }
    
    /** to judge if ip1 is bigger than ip2
     * return ture if ip1 > ip2
     *       false if ip1 <= ip2
     *
     */
    public static boolean isBigger(String ip1, String ip2) {
        boolean result = false;
        int[]  addr1 = getAddrArray(ip1);
        int[]  addr2 = getAddrArray(ip2);
        for (int i = 0; i<4; i++) {
            if ( addr1[i] > addr2[i] ) {
                result = true;
                break;
            }
        }
        return result;
    }
    
    public static String checkIPType(String ip){
        String result = null;
        if(ip == null){
            return null;
        }
        int[]  addr = getAddrArray(ip);
        if((addr[0] > 0) && (addr[0] < 127)){
            result = "A"; //"Class A Network";
        }else if((addr[0] >127) && (addr[0] < 192)){
            result = "B";
        }else if((addr[0] >= 192) && (addr[0] < 224)){
            result = "C";
        }else {
            result = "Invalid Network";
        }
        return result;
    }
    
    public static String checkMaskType(String netMask){
        String result = null;
        if(netMask == null){
            return null;
        }
        if(netMask.equalsIgnoreCase("255.255.255.255")){
            result = "Lookback Network";
        }else if(netMask.equalsIgnoreCase("255.255.255.252")){
            result = "Direct Link Network";
        }else{
            result = "Normal Network";
        }
        return result;
    }
    
    public static String checkNetType(String netIp){
        String result = null;
        result = checkIPType(netIp);
        
        return result;
    }
    
    /** Setter for property ip.
     * @param ip New value of property ip.
     *
     */
    public void setIp(java.lang.String ip) {
        this.ip = ip;
    }
    
    /** Setter for property netmask.
     * @param netmask New value of property netmask.
     *
     */
    public void setNetmask(java.lang.String netmask) {
        this.netmask = netmask;
    }
    
    /**
     * 判断IP是否合法
     * @param ip
     * @param type ip类型：0－网段；1－子网；2－ip地址。
     * @return
     */
    public static boolean isRegularIP(String ip,int type){
        if(ip==null || ip.trim().equals(""))
            return false;
        
        int[] ips=getAddrArray(ip);
        if(ips==null || ips.length<4)
            return false;
        
        if(ip.startsWith("0.") || ip.endsWith(".255")|| ip.equals("127.0.0.1"))
            return false;
        
        if(ip.endsWith(".0") && type==2)
            return false;
        return true;
    }
    
    /**
     *判断掩码是否合法
     * @param mask
     * @return
     */
    public static boolean isRegularMask(String mask){
        int[] mi=getAddrArray(mask);
        if(mi==null)
            return false;
        if(mi[0]!=255 && isInRange(mi[0]) && mi[0]!=0){
            if(mi[1]!=0 || mi[2]!=0 || mi[3]!=0)
                return false;
        }else if(mi[0]==255){
            if(mi[1]!=255 && isInRange(mi[1])){
                if(mi[2]!=0 || mi[3]!=0)
                    return false;
            }else if(mi[1]==255){
                if(mi[2]!=255 && isInRange(mi[2])){
                    if(mi[3]!=0)
                        return false;
                }
                else if(mi[2]==255){
                    if(mi[3]==255 )
                        return false;
                    else if(mi[3]!=255 && !isInRange(mi[3]))
                        return false;
                }
                else
                    return false;
            }else
                return false;
        }else
            return false;
        return true;
    }
    
    private static boolean isInRange(int ip){
        switch (ip){
            case 0:
                return true;
            case 128:
                return true;
            case 192:
                return true;
            case 224:
                return true;
            case 240:
                return true;
            case 248:
                return true;
            case 252:
                return true;
            case 254:
                return true;
            case 255:
                return true;
            default:
                return false;
        }
    }
    
}
